﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

namespace Lyon.Data.ORM
{
    /// <summary>
    /// 对象数据库。
    /// </summary>
    abstract public class AbstractDataBase : AbstractAdoOperations, IDataBase
    {
        #region IOleDataBase 成员
        /// <summary>
        /// 插入。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void Insert<T>(T t)
        {
            using (DataSession session = this.CreateSession())
            {
                session.Insert<T>(t);
            }
        }
        /// <summary>
        /// 更新。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void Update<T>(T t)
        {
            using (DataSession session = this.CreateSession())
            {
                session.Update<T>(t);
            }
        }
        /// <summary>
        /// 删除。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void Delete<T>(T t)
        {
            using (DataSession session = this.CreateSession())
            {
                session.Delete<T>(t);
            }
        }
        /// <summary>
        /// 删除。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        public void Delete<T>(TypeFilter<T> filter)
        {
            using (DataSession session = this.CreateSession())
            {
                session.Delete<T>(filter);
            }
        }

        /// <summary>
        /// 获取对象。
        /// </summary>
        /// <typeparam name="T">类型。</typeparam>
        /// <param name="primaryField">主要字段值。</param>
        /// <returns></returns>
        public T Select<T>(object primaryField)
        {
            using (DataSession session = this.CreateSession())
            {
                return session.Select<T>(primaryField);
            }
        }
        /// <summary>
        /// 查找。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public T[] Select<T>(TypeFilter<T> filter)
        {
            using (DataSession session = this.CreateSession())
            {
                DataList<T> dataList = session.Select<T>(filter);
                return dataList.ToArray();
            }
        }
        /// <summary>
        /// 查找。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public T[] Select<T>(TypeFilter<T> filter, TypeOrder<T> order)
        {
            using (DataSession session = this.CreateSession())
            {
                DataList<T> dataList = session.Select<T>(filter, order);
                return dataList.ToArray();
            }
        }
        /// <summary>
        /// 查找对象。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter">过滤器。</param>
        /// <returns></returns>
        public int SelectCount<T>(TypeFilter<T> filter)
        {
            using (DataSession session = this.CreateSession())
            {
                return session.SelectCount<T>(filter);
            }
        }
        #endregion

        /// <summary>
        /// 创建一个对象操作会话。
        /// </summary>
        /// <returns></returns>
        public DataSession CreateSession()
        {
            return new DataSession(this.CreateTransaction());
        }

        IDataSession IDataBase.CreateSession()
        {
            return CreateSession();
        }
    }

    /// <summary>
    /// 对象操作会话。
    /// </summary>
    public class DataSession : IDataSession
    {
        DataBuilder builder;
        internal AdoTransaction _Tran;
        internal DataSession(AdoTransaction transaction)
        {
            this._Tran = transaction;
            this.builder = new DataBuilder(this);
        }

        /// <summary>
        /// 插入。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void Insert<T>(T t)
        {
            TypeMapping mapping = TypeMapping.GetMapping(typeof(T));
            try
            {
                IDictionary dict = builder.GetDict(mapping, t);

                //生成sql脚本。
                InsertBuilder insertBuilder = new InsertBuilder(mapping, dict);
                //执行命令。
                _Tran.ExecuteNonQuery(insertBuilder);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Insert OleDataBase is Exception", ex);
            }
        }
        /// <summary>
        /// 更新。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void Update<T>(T t)
        {
            TypeMapping mapping = TypeMapping.GetMapping(typeof(T));
            try
            {
                IDictionary dictValue = builder.GetDict(mapping, t);

                TypeFilter<T> filter = new TypeFilter<T>();
                foreach (FieldMapping fieldMapping in mapping.FieldMappings)
                {
                    if (((IColumnMapping)fieldMapping).IsPrimary)
                    {
                        filter = filter.And(fieldMapping.Name, FilterLogical.Equal, dictValue[fieldMapping.ColumnName]);
                        dictValue.Remove(fieldMapping.ColumnName);
                    }
                }

                //生成sql脚本。
                UpdateBuilder updateBuilder = new UpdateBuilder(mapping, dictValue, filter);
                //执行命令。
                _Tran.ExecuteNonQuery(updateBuilder);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Update OleDataBase is Exception", ex);
            }
        }
        /// <summary>
        /// 删除。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public void Delete<T>(T t)
        {
            TypeMapping mapping = TypeMapping.GetMapping(typeof(T));
            try
            {
                IDictionary dictValue = builder.GetDict(mapping, t);

                TypeFilter<T> filter = new TypeFilter<T>();
                foreach (FieldMapping fieldMapping in mapping.FieldMappings)
                {
                    if (((IColumnMapping)fieldMapping).IsPrimary)
                    {
                        filter = filter.And(fieldMapping.Name, FilterLogical.Equal, dictValue[fieldMapping.ColumnName]);
                    }
                }

                //生成sql脚本。
                DeleteBuilder deleteBuilder = new DeleteBuilder(mapping, filter);
                //执行命令。
                _Tran.ExecuteNonQuery(deleteBuilder);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Delete OleDataBase is Exception", ex);
            }
        }

        /// <summary>
        /// 删除。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        public void Delete<T>(TypeFilter<T> filter)
        {
            TypeMapping mapping = TypeMapping.GetMapping(typeof(T));
            try
            {
                //生成sql脚本。
                DeleteBuilder deleteBuilder = new DeleteBuilder(mapping, filter);
                //执行命令。
                _Tran.ExecuteNonQuery(deleteBuilder);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Delete OleDataBase is Exception", ex);
            }
        }

        /// <summary>
        /// 获取对象。
        /// </summary>
        /// <typeparam name="T">类型。</typeparam>
        /// <param name="primaryField">主要字段值。</param>
        /// <returns></returns>
        public T Select<T>(object primaryField)
        {
            try
            {
                TypeMapping mapping = TypeMapping.GetMapping(typeof(T), true);
                if (mapping.UniquePrimary == null)
                {
                    throw new ArgumentNullException("Type\"{0}\"'s TypeMapping.UniquePrimary is null.");
                }
                TypeFilter<T> filter = new TypeFilter<T>().And(mapping.UniquePrimary.Name, FilterLogical.Equal, primaryField);

                SelectBuilder selectBuilder = new SelectBuilder(filter);
                IDictionary[] dicts = _Tran.ExecuteReader(mapping, selectBuilder);

                if (dicts.Length == 1)
                {
                    DataBuilder builder = new DataBuilder(this);
                    return (T)builder.SetDict(mapping, dicts[0]);
                }
                return default(T);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Select OleDataBase is Exception", ex);
            }
        }

        /// <summary>
        /// 查找对象。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter">过滤器。</param>
        /// <returns></returns>
        public int SelectCount<T>(TypeFilter<T> filter)
        {
            try
            {
                TypeMapping mapping = TypeMapping.GetMapping(typeof(T));

                SelectCountBuilder selectBuilder = new SelectCountBuilder(filter);
                return (int)_Tran.ExecuteScalar(selectBuilder);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("SelectCount DataBase is Exception", ex);
            }
        }

        /// <summary>
        /// 查找。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public DataList<T> Select<T>(TypeFilter<T> filter)
        {
            try
            {
                TypeMapping mapping = TypeMapping.GetMapping(typeof(T));

                SelectBuilder selectBuilder = new SelectBuilder(filter);
                IDictionary[] dicts = _Tran.ExecuteReader(mapping, selectBuilder);

                return new DataList<T>(builder, mapping, dicts);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Select DataBase is Exception", ex);
            }
        }
        /// <summary>
        /// 查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        public DataList<T> Select<T>(TypeFilter<T> filter, TypeOrder<T> order)
        {
            try
            {
                TypeMapping mapping = TypeMapping.GetMapping(typeof(T));

                SelectBuilder selectBuilder = new SelectBuilder(mapping, filter, order);
                IDictionary[] dicts = _Tran.ExecuteReader(mapping, selectBuilder);

                return new DataList<T>(builder, mapping, dicts);
            }
            catch (Exception ex)
            {
                throw new ObjectDataBaseException("Select DataBase is Exception", ex);
            }
        }
        /// <summary>
        /// 回滚当前会话的所有操作。
        /// </summary>
        public void Rollback()
        {
            _Tran.Rollback();
        }

        IDataList<T> IDataSession.Select<T>(TypeFilter<T> filter)
        {
            return Select<T>(filter);
        }

        IDataList<T> IDataSession.Select<T>(TypeFilter<T> filter, TypeOrder<T> order)
        {
            return Select<T>(filter, order);
        }
        /// <summary>
        /// 提交会话所有操作，并关闭会话。
        /// </summary>
        public void Dispose()
        {
            this._Tran.Dispose();
        }
    }

    internal class DataBuilder
    {
        DataSession _DataBase;

        ObjectBuffer _ObjectBuffer;
        Dictionary<Type, IObjectDataBaseConverter> _DBFieldConverters;

        internal DataBuilder(DataSession database)
        {
            _DBFieldConverters = new Dictionary<Type, IObjectDataBaseConverter>();
            _ObjectBuffer = new ObjectBuffer();
            _DataBase = database;
        }

        private IObjectDataBaseConverter GetConverter(Type type)
        {
            IObjectDataBaseConverter converter = null;
            if (!_DBFieldConverters.TryGetValue(type, out converter))
            {
                TypeMapping mapping = TypeMapping.GetMapping(type);
                if (mapping != null && mapping.UniquePrimary != null)
                {
                    converter = new ObjectWithPrimaryDataBaseConverter(this, mapping);
                }
                else
                {
                    converter = NoObjectDataBaseConverter.Value;
                }
                _DBFieldConverters.Add(type, converter);
            }
            return converter;
        }

        public object SetDict(TypeMapping mapping, IDictionary dict)
        {
            object t = mapping.CreateInstance();
            //加入缓冲区。
            if (mapping.UniquePrimary != null)
            {
                _ObjectBuffer.SetCache(mapping.TypeInfo, dict[mapping.UniquePrimary.ColumnName], t);
            }

            foreach (FieldMapping field in mapping.FieldMappings)
            {
                field.SetValue(t
                        , GetConverter(field.FieldType).ToObj(dict[field.ColumnName]));
            }
            return t;
        }

        public IDictionary GetDict(TypeMapping mapping, object obj)
        {
            Dictionary<string, object> dict = new Dictionary<string, object>();
            foreach (FieldMapping field in mapping.FieldMappings)
            {
                dict.Add(field.ColumnName
                    , GetConverter(field.FieldType).ToDB(field.GetValue(obj)));
            }
            return dict;
        }

        /// <summary>
        /// 定义由数据库字段类型转换器所实现的方法。
        /// </summary>
        public interface IObjectDataBaseConverter
        {
            /// <summary>
            /// 对象类型转换成数据库类型。
            /// </summary>
            /// <param name="obj">对象实例。</param>
            /// <returns></returns>
            object ToDB(object obj);
            /// <summary>
            /// 数据库类型转换成对象类型。
            /// </summary>
            /// <param name="db">数据库对象。</param>
            /// <returns></returns>
            object ToObj(object db);
        }

        /// <summary>
        /// 带主键的对象数据转换。
        /// </summary>
        private class ObjectWithPrimaryDataBaseConverter : IObjectDataBaseConverter, IColumnFilter
        {
            DataBuilder _Builder;
            DataSession _DataBase;
            TypeMapping _Mapping;

            object _db;

            public ObjectWithPrimaryDataBaseConverter(DataBuilder builder, TypeMapping mapping)
            {
                _Builder = builder;
                _DataBase = builder._DataBase;
                _Mapping = mapping;
            }

            #region IDBFieldConverter 成员

            public object ToDB(object obj)
            {
                if (obj == null)
                {
                    return null;
                }
                FieldMapping field = _Mapping.UniquePrimary;
                IObjectDataBaseConverter converter = _Builder.GetConverter(field.FieldType);
                return converter.ToDB(field.GetValue(obj));
            }

            public object ToObj(object db)
            {
                if (db == DBNull.Value || db == null)
                {
                    return null;
                }
                //从缓存中取值。
                object obj = null;
                if (_Builder._ObjectBuffer.TryGetCache(_Mapping.TypeInfo, db, out obj))
                {
                    return obj;
                }
                //从数据库中取值。
                _db = db;
                SelectBuilder selectBuilder = new SelectBuilder(this);
                IDictionary[] dicts = _DataBase._Tran.ExecuteReader(_Mapping, selectBuilder);
                if (dicts.Length == 0)
                {
                    return null;
                }
                IDictionary dict = dicts[0];
                return _Builder.SetDict(_Mapping, dict);
            }

            #endregion

            #region ITableFilter 成员

            string IColumnFilter.ColumnName
            {
                get { return _Mapping.UniquePrimary.ColumnName; }
            }

            FilterLogical IColumnFilter.Logical
            {
                get { return FilterLogical.Equal; }
            }

            object IColumnFilter.ColumnValue
            {
                get
                {
                    return _db;
                }
            }

            ITableMapping ITableFilter.SelectTable
            {
                get { return _Mapping; }
            }

            #endregion
        }
        /// <summary>
        /// 非对象数据转转换。
        /// </summary>
        private class NoObjectDataBaseConverter : IObjectDataBaseConverter
        {
            static public readonly NoObjectDataBaseConverter Value = new NoObjectDataBaseConverter();

            private NoObjectDataBaseConverter() { }

            #region IDBFieldConverter 成员

            public object ToDB(object obj)
            {
                return obj;
            }

            public object ToObj(object db)
            {
                return db;
            }

            #endregion
        }

        /// <summary>
        /// 简单对象缓冲区。
        /// </summary>
        public class ObjectBuffer
        {
            Dictionary<Type, Dictionary<object, object>> _dict;
            /// <summary>
            /// 初始化。
            /// </summary>
            public ObjectBuffer()
            {
                _dict = new Dictionary<Type, Dictionary<object, object>>(100);
            }

            /// <summary>
            /// 尝试获取指定类型和键的对象。
            /// </summary>
            /// <param name="type"></param>
            /// <param name="key"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            public bool TryGetCache(Type type, object key, out object value)
            {
                value = null;
                Dictionary<object, object> typeCache = null;
                if (_dict.TryGetValue(type, out typeCache))
                {
                    return typeCache.TryGetValue(key, out value);
                }
                return false;
            }
            /// <summary>
            /// 设置指定类型和键的对象。
            /// </summary>
            /// <param name="type"></param>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public void SetCache(Type type, object key, object value)
            {
                Dictionary<object, object> typeCache = null;
                if (!_dict.TryGetValue(type, out typeCache))
                {
                    typeCache = new Dictionary<object, object>(10000);
                    _dict.Add(type, typeCache);
                }
                typeCache.Remove(key);
                typeCache.Add(key, value);
            }
            /// <summary>
            /// 清除指定类型和键的对象。
            /// </summary>
            /// <param name="type"></param>
            /// <param name="key"></param>
            public void Clear(Type type, object key)
            {
                Dictionary<object, object> typeCache = null;
                if (_dict.TryGetValue(type, out typeCache))
                {
                    typeCache.Remove(key);
                }
            }
            /// <summary>
            /// 缓存集中对象的总个数。
            /// </summary>
            public int Count
            {
                get
                {
                    int i = 0;
                    foreach (Dictionary<object, object> temp in _dict.Values)
                    {
                        i += temp.Count;
                    }
                    return i;
                }
            }
            /// <summary>
            /// 清除所有缓存对象。
            /// </summary>
            public void Clear()
            {
                _dict.Clear();
            }
        }
    }
    /// <summary>
    /// 数据对象集合
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DataList<T> : IDataList<T>
    {
        private DataBuilder builder;
        private TypeMapping mapping;
        private IDictionary[] dicts;

        internal DataList(DataBuilder builder, TypeMapping mapping, IDictionary[] dicts)
        {
            this.builder = builder;
            this.mapping = mapping;
            this.dicts = dicts;
        }
        /// <summary>
        /// 获取数据对象个数。
        /// </summary>
        public int Count
        {
            get { return dicts.Length; }
        }
        /// <summary>
        /// 导出数据对象。
        /// </summary>
        /// <returns></returns>
        public T[] ToArray()
        {
            return Array.ConvertAll<IDictionary, T>(dicts, delegate(IDictionary dict)
            {
                return (T)builder.SetDict(mapping, dict);
            });
        }
        /// <summary>
        /// 导出数据对象。
        /// </summary>
        /// <param name="array">目标集合</param>
        /// <param name="index">起始位置</param>
        public void CopyTo(Array array, int index)
        {
            if (index + array.Length > dicts.Length)
                throw new ArgumentOutOfRangeException();
            for (int i = 0; i < array.Length; i++)
            {
                IDictionary dict = dicts[index + i];
                array.SetValue((T)builder.SetDict(mapping, dict), i);
            }
        }
    }
}
